'use strict'

const { Controller } = require('egg')

// 用户名格式验证
const pattern = /^[\w-]{3,16}$/
class UserController extends Controller {
  // 用户注册
  async register() {
    const { ctx, service } = this
    // 参数验证
    ctx.validate({
      username: {
        type: 'string',
        required: true,
        trim: true,
        desc: '用户名'
      },
      password: {
        type: 'string',
        required: true,
        trim: true,
        desc: '密码'
      },
      avatar: {
        type: 'string',
        desc: '头像'
      }
    })
    let { username, password, avatar } = ctx.request.body
    if (!pattern.test(username)) {
      return ctx.apiFail('用户名长度为3~16位(字母,数字,下划线,减号)', 422)
    }
    if (!pattern.test(password)) {
      return ctx.apiFail('密码长度为3~16位(字母,数字,下划线,减号)', 422)
    }
    // 随机生成头像
    avatar = avatar ? avatar : Math.floor(Math.random() * 14).toString()
    let user = await service.user.register({ username, nickname: username, password, avatar })
    user = user.toJSON()
    Reflect.deleteProperty(user, 'password')

    ctx.apiSuccess(user)
  }
  // 用户登录
  async login() {
    const { ctx, app, service } = this
    // 参数验证
    ctx.validate({
      username: { type: 'string', required: true, range: { min: 3, max: 16 }, desc: '用户名' },
      password: { type: 'string', required: true, range: { min: 3, max: 16 }, desc: '密码' }
    })
    let { username, password } = ctx.request.body
    // 1.用户是否存在
    let user = await app.model.User.findOne({ where: { username } })
    if (!user) ctx.throw(400, '用户不存在')
    // 2.验证密码
    ctx.checkPassword(password, user.password)
    // 3.用户状态
    if (user.status !== 1) ctx.throw(400, '该用户已被禁用')
    // 4.返回用户信息和token
    user = user.toJSON()
    Reflect.deleteProperty(user, 'password')
    // 生成访问token
    const accessToken = ctx.signAccessToken({ id: user.id })
    // 生成刷新token
    const refreshToken = ctx.signRefreshToken({ id: user.id })
    // 存储redis
    const value = JSON.stringify({ accessToken, refreshToken })
    app.redis.set(`user:${user.id}`, value, 'EX', 60 * 60 * 24 * 7)
    // 创建访问记录
    service.visit.createVisit()

    user.token = accessToken
    ctx.apiSuccess(user)
  }
  // 游客登录
  async loginTourist() {
    const { ctx, service, app } = this
    // 1.查询是否登录过
    let user = await service.user.register({ ip: ctx.request.ip }, 'tourist')
    user = user.toJSON()
    // 2.返回token
    // 生成访问token
    const accessToken = ctx.signAccessToken({ id: user.id })
    // 生成刷新token
    const refreshToken = ctx.signRefreshToken({ id: user.id })
    // 存储redis
    const value = JSON.stringify({ accessToken, refreshToken })
    app.redis.set(`user:${user.id}`, value, 'EX', 60 * 60 * 24 * 7)
    // 创建访问记录
    service.visit.createVisit()

    user.token = accessToken
    ctx.apiSuccess(user)
  }
  // 退出登录
  async logout() {
    const { ctx, app } = this
    // 删除redis中的token
    await app.redis.del(`user:${ctx.authUser.id}`)
    // 返回结果
    ctx.apiSuccess('退出成功')
  }
  // 修改用户信息
  async updateUser() {
    const { ctx, app, service } = this
    // 参数验证
    ctx.validate({
      nickname: { type: 'string', required: true, range: { max: 30 }, desc: '昵称' },
      avatar: { type: 'string', required: true, desc: '头像路径' }
    })
    const { nickname, avatar } = ctx.request.body
    // 判断头像是否更新了
    if (avatar !== ctx.authUser.avatar) {
      if (!avatar.startsWith('http')) return ctx.apiFail('头像需要是网络地址')
      // 删除旧头像
      await service.common.deleteFiles([ctx.authUser.avatar])
    }
    // 更新数据库
    await app.model.User.update(
      { nickname, avatar },
      {
        where: { id: ctx.authUser.id }
      }
    )

    ctx.apiSuccess('修改成功')
  }
  // 获取用户列表
  async getUserList() {
    const { ctx, app } = this
    // 参数验证
    ctx.validate({
      page: { type: 'int', desc: '页码' },
      pageSize: { type: 'int', desc: '每页条数' },
      username: { type: 'string', desc: '用户名' },
      nickname: { type: 'string', desc: '昵称' },
      status: { type: 'int', range: { in: [1, 2] }, desc: '状态' },
      type: { type: 'int', range: { in: [1, 2] }, desc: '类型' }
    })
    const { username, nickname, status, type } = ctx.request.query
    const Op = app.Sequelize.Op
    // 整理查询条件
    let where = {}
    if (username) where.username = { [Op.like]: `%${username}%` }
    if (nickname) where.nickname = { [Op.like]: `%${nickname}%` }
    if (status) where.status = status
    if (type) where.type = type

    const result = await ctx.page('User', where, {
      attributes: {
        exclude: ['password']
      }
    })
    ctx.apiSuccess(result)
  }
  // 修改用户信息(后台管理)
  async updateUserAdmin() {
    const { ctx, app, service } = this
    // 参数验证
    ctx.validate({
      id: { type: 'int', required: true, desc: '用户id' },
      nickname: { type: 'string', desc: '昵称' },
      email: { type: 'string', desc: '邮箱' },
      avatar: { type: 'string', desc: '头像' },
      status: { type: 'int', range: { in: [1, 2] }, desc: '状态' }
    })
    const { id, nickname, email, avatar, status } = ctx.request.body
    // 查询数据库
    const user = await app.model.User.findOne({ where: { id } })
    if (!user) ctx.throw(400, '该记录不存在')
    // 判断头像是否更新了
    if (avatar !== user.avatar) {
      if (!avatar?.startsWith('http')) return ctx.apiFail('头像需要是网络地址')
      // 删除旧头像
      await service.common.deleteFiles([user.avatar])
    }
    const params = {}
    if (nickname) params.nickname = nickname
    if (email) params.email = email
    if (avatar) params.avatar = avatar
    if (status) params.status = status
    const result = await user.update(params)

    ctx.apiSuccess(result)
  }
  // 修改用户密码
  async updateUserPassword() {
    const { ctx, app } = this
    // 参数验证
    ctx.validate({
      id: { type: 'int', required: true, desc: '用户id' },
      password: { type: 'string', required: true, desc: '密码' }
    })
    const { id, password } = ctx.request.body
    if (!pattern.test(password)) {
      return ctx.apiFail('密码长度为3~16位(字母,数字,下划线,减号)', 422)
    }
    // 查询数据库
    const user = await app.model.User.findOne({ where: { id } })
    if (!user) ctx.throw(400, '该记录不存在')
    if (user.type !== 1) ctx.throw(400, '游客不能修改密码')
    // 修改密码
    await user.update({ password })

    ctx.apiSuccess('修改成功')
  }
  // 删除用户
  async deleteUser() {
    const { ctx, app, service } = this
    // 参数验证
    ctx.validate({
      ids: { type: 'string', required: true, desc: '用户id' }
    })
    let { ids } = ctx.request.body
    // 整理参数
    ids = ids.split(',').map((id) => parseInt(id))
    // 删除oss上的图片
    const userList = await app.model.User.findAll({ where: { id: ids } })
    const fileUrls = userList
      .filter((item) => item.avatar?.startsWith('http'))
      .map((item) => item.avatar)
    await service.common.deleteFiles(fileUrls)
    const result = await app.model.User.destroy({ where: { id: ids } })

    ctx.apiSuccess(result)
  }
}

module.exports = UserController
